package com.itheima.tanhua.gateway.filter;

import cn.hutool.http.HttpStatus;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.xml.ws.spi.http.HttpHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

// 1. 使用Order注解，设置执行顺序
@Order(-1)
@Component
// 2. 要实现GlobalFilter声明全局过滤器
public class AuthorizeFilter implements GlobalFilter {

    String key = "1234";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求头信息     拦截器可以获取请求头的信息
        //MultiValueMap 这个结构，是Map结构的变种，它允许存在相同名字的多个key
        MultiValueMap<String,String> params = exchange.getRequest().getHeaders();

        //2.判断哪些路径要放行(登录等)
        List<String> whiteList = new ArrayList<>();
        whiteList.add("/members/login");
        whiteList.add("/members/sms");

        //2.1.获取当前请求的地址
        String url = exchange.getRequest().getPath().toString();

        //2.2.判断这个地址是不是要放行
        if (whiteList.contains(url)){
            System.out.println("直接放行");
            return chain.filter(exchange);
        }

        //2.获取头部的token
        //为什么token是从这个参数获取的?
        //因为这是规范
        String token = params.getFirst("Authorization");

        //3.解析token信息
        //参数一:要验证的token
        //参数二:用来解析token的秘钥
        boolean verify = JWTUtil.verify(token, key.getBytes());
        if (!verify){
            //阻止(标准:给前端返回401状态码)
            return getVoidMono(exchange);
        }

        //4.获取用户信息
        JWT jwt = JWTUtil.parseToken(token);
        //获取载荷(中间那段)
        JWTPayload payload = jwt.getPayload();
        if (payload == null){
            //阻止
            return getVoidMono(exchange);
        }

        //获取载荷里面的id字段
        Object id = payload.getClaim("id");
        if (id == null){
            //阻止
            return getVoidMono(exchange);
        }

        //把解析到的用户信息，存放到请求头上
        //因为响应的请求头是只读状态，不能再上面set
        //1.重构一个响应对象，在重构的响应对象里面，设置请求头
        //将memberId添加到请求头上
        ServerHttpRequest requestNew = exchange.getRequest().mutate().headers(new Consumer<HttpHeaders>() {
            @Override
            public void accept(HttpHeaders httpHeaders) {
                httpHeaders.add("id", id.toString());
            }
        }).build();

        //刷新请求头
        exchange.mutate().request(requestNew).build();
        //2.将新构建的响应对象，返回给前端

        //放行
        System.out.println("放行成功");
        return chain.filter(exchange);
    }

    private Mono<Void> getVoidMono(ServerWebExchange exchange){
        //1.获取响应结构，设置状态
        exchange.getResponse().setRawStatusCode(HttpStatus.HTTP_UNAUTHORIZED);
        //2.把修改后的返回值结果，响应给前端
        return exchange.getResponse().setComplete();
    }
}